#include "StdAfx.h"
#include "Frame.hxx"
#include "VideoWriter.hxx"

VideoWriter::VideoWriter(void)
{
	_fileName[ 0 ] = '\0';
	
	_context = 0;
	_picture = 0;
	_videoBuffer = 0;
	_bufferSize = 0;
	_frameNumber = 0;
	_outputSize = 0;
	_hadOutput = 0;
	 _mp4file = 0;
	_startStatus = false;
}


VideoWriter::~VideoWriter(void)
{
}

void VideoWriter::Start()
{	
	AVCodec *codec;
    _context= 0;
    _startStatus = true;

    /* find the mpeg1 video encoder */
    codec = avcodec_find_encoder((AVCodecID)AV_CODEC_ID_MPEG4);
	//codec = avcodec_find_encoder((AVCodecID)AV_CODEC_ID_H264);
    if (!codec) {
        fprintf(stderr, "codec not found\n");
        _startStatus = false;
        return;
    }

    _context = avcodec_alloc_context3(codec);
    _picture = avcodec_alloc_frame();

    /* put sample parameters */
    _context->bit_rate = 4000000;
    /* resolution must be a multiple of two */
    _context->width = RAW_FRAME_WIDTH;
    _context->height = RAW_FRAME_HEIGHT;
    /* frames per second */
    //c->time_base= (AVRational){1,25};
    _context->time_base.num = 1;
    _context->time_base.den = 25;
    _context->gop_size = 10; /* emit one intra frame every ten frames */
    _context->max_b_frames=1;
    _context->pix_fmt = PIX_FMT_YUV420P;

    /* open it */
	int oval = avcodec_open2( _context, codec, NULL);

    if ( oval < 0) {
        fprintf(stderr, "could not open codec\n");
        _startStatus = false;
        return;
    }

    _mp4file = fopen( _fileName , "wb");
    if (!_mp4file) {
        fprintf(stderr, "could not open %s\n", _fileName);
        _startStatus = false;
        return;
    }

    av_image_alloc( _picture->data, _picture->linesize,
                       _context->width, _context->height, _context->pix_fmt, 1);

    _bufferSize = 100000 + 12*_context->width*_context->height;
    _videoBuffer = (uint8_t*)malloc(_bufferSize);
}

void VideoWriter::Write( char* buf )
{
	int offset = 0;
    char* tbuf = buf;

    _frameNumber ++;

    offset = RAW_FRAME_WIDTH * RAW_FRAME_HEIGHT;
    memcpy( _picture->data[ 0 ], tbuf, offset );

    tbuf += offset;

    offset = offset / 4;
    memcpy( _picture->data[ 2 ], tbuf, offset );

    tbuf += offset;
    memcpy( _picture->data[ 1 ], tbuf, offset );

    _outputSize = avcodec_encode_video( _context , _videoBuffer, _bufferSize, _picture );
    _hadOutput |= _outputSize;
    //printf("encoding frame %3d (size=%5d)\n", __frameNumber[ chnNumber ], __outputSize[ chnNumber ]);
    fwrite( _videoBuffer, 1, _outputSize, _mp4file );

    /* get the delayed frames */
    if( _frameNumber % 30 == 0 )
    {
        for(; _outputSize || !_hadOutput; _frameNumber++)
        {
            fflush(stdout);

            _outputSize = avcodec_encode_video( _context , _videoBuffer, _bufferSize, NULL);
            _hadOutput |= _outputSize;
            //printf("write frame %3d (size=%5d)\n", __frameNumber[ chnNumber ], __outputSize[ chnNumber ]);
            fwrite(_videoBuffer, 1, _outputSize, _mp4file);
        }
    }

    _frameNumber = 0;
}

void VideoWriter::Stop()
{
	/* add sequence end code to have a real mpeg file */
    _videoBuffer[0] = 0x00;
    _videoBuffer[1] = 0x00;
    _videoBuffer[2] = 0x01;
    _videoBuffer[3] = 0xb7;
    fwrite( _videoBuffer, 1, 4, _mp4file);
    fclose( _mp4file );
    free( _videoBuffer );

    avcodec_close( _context );

    av_free( _context );
    av_free( _picture->data[0]);
    av_free( _picture );
}

void VideoWriter::SetFileName( char* fileName )
{
	strcpy( _fileName, fileName );
}


